﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using PCDoctor.Utils;
using System.Xml;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;

namespace PCDoctor.Updater
{
    class Updater
    {
        /// <summary>
        /// Содержит информацию о новой версии
        /// </summary>
        public string newVersion { get; set; }

        /// <summary>
        /// URL, откуда нужно качать установщик обновленной версии
        /// </summary>
        protected string updateExecutableUrl { get; set; }

        /// <summary>
        /// Имя файла, куда будет скачано обновление
        /// </summary>
        protected string downloadTo { get; set; }
        
        /// <summary>
        /// Проверка обновлений на сервере
        /// </summary>
        /// <returns>bool</returns>
        public bool Check()
        {
            bool result = true;
            string updateData = "";
            try
            {
                WebClient cl = new WebClient();
                updateData = cl.DownloadString(Config.UPDATE_XML_PATH);
            }
            catch (Exception e)
            {
                ErrorHandler.HandleError(e.Message);
                result = false;
            }
            if (result)
            {
                XmlDocument doc = new XmlDocument();
                doc.LoadXml(updateData);
                XmlNodeList nodes = doc.GetElementsByTagName("current_version");
                if (nodes.Count != 1)
                {
                    return false;
                }
                newVersion = nodes[0].InnerText;
                XmlNodeList nodes2 = doc.GetElementsByTagName("exe_url");
                if (nodes2.Count != 1)
                {
                    return false;
                }
                updateExecutableUrl = nodes2[0].InnerText;
            }
            return result;
        }

        /// <summary>
        /// Сравнение версий ПО на сервере и параметра
        /// </summary>
        /// <param name="version">Версия ПО, с которой нужно сравнивать</param>
        /// <returns>Число, меньше или = 0 - нет обновлений</returns>
        public int CompareVersion(string version)
        {
            string[] pv = version.Split('.');
            string[] sv = newVersion.Split('.');
            int[] p = { 0, 0, 0 };
            int[] s = { 0, 0, 0 };
            for (int i = 0; i < pv.Length; i++)
            {
                if (!int.TryParse(pv[i], out p[i]))
                {
                    p[i] = 0;
                }
            }
            for (int i = 0; i < sv.Length; i++)
            {
                if (!int.TryParse(sv[i], out s[i]))
                {
                    s[i] = 0;
                }
            }
            int result = 0;
            for (int i = 0; i < 3; i++)
            {
                result = s[i] - p[i];
                if (result != 0)
                {
                    break;
                }
            }
            return result;
        }

        /// <summary>
        /// Запуск процесса обновления
        /// </summary>
        public bool Update()
        {
            bool result = true;
            try
            {
                downloadTo = Path.Combine(
                    Environment.GetEnvironmentVariable("temp", EnvironmentVariableTarget.Machine),
                    Path.GetFileName(updateExecutableUrl));
                WebClient wc = new WebClient();
                wc.DownloadProgressChanged +=
                    new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);
                wc.DownloadFileCompleted +=
                    new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted);
                wc.DownloadFileAsync(new Uri(updateExecutableUrl), downloadTo);
            }
            catch (Exception e)
            {
                result = false;
                ErrorHandler.HandleError(e.Message);
            }
            return result;
        }

        /// <summary>
        /// Устанавливаем обновки по завершении загрузки
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            try
            {
                Process p = new Process();
                p.StartInfo = new ProcessStartInfo(downloadTo);
                p.Start();
                Environment.Exit(0);
            }
            catch (Exception ex)
            {
                OnUpdateFinished(new UpdateFinishedEventArgs
                {
                    Updated = false
                });
                ErrorHandler.HandleError(ex.Message);
            }
        }

        void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            Console.WriteLine("Скачано " + e.ProgressPercentage.ToString() + "%");
        }

        /// <summary>
        /// Событие "подготовка обновления завершена"
        /// </summary>
        public event UpdateFinish UpdateFinished;

        protected virtual void OnUpdateFinished(UpdateFinishedEventArgs e)
        {
            UpdateFinished(this, e);
        }
    }

    /// <summary>
    /// Класс аргументов события "Подготовка обновления завершена"
    /// </summary>
    public class UpdateFinishedEventArgs : EventArgs
    {
        public bool Updated { get; set; }
    }

    public delegate void UpdateFinish(object sender, UpdateFinishedEventArgs e);
}
